﻿
Imports System.Runtime.CompilerServices
Imports System.IO
Imports System.Net.Sockets
Imports osi.root.connector
Imports osi.root.delegates
Imports osi.root.procedure
Imports osi.root.lock
Imports osi.root.formation
Imports osi.root.utils
Imports osi.root.envs
Imports osi.service.tcp.constants

Public Module _answer
    'single answer, will shutdown the connection is handle returns false
    <Extension()> Public Function answer(ByVal client As TcpClient,
                                         ByVal handle As Func(Of TcpClient, event_comb)) As event_comb
        Dim ec As event_comb = Nothing
        Return New event_comb(Function() As Boolean
                                  If Not alive(client) OrElse
                                     handle Is Nothing Then
                                      Return False
                                  Else
                                      ec = handle(client)
                                      Return waitfor(ec) AndAlso
                                             goto_next()
                                  End If
                              End Function,
                              Function() As Boolean
                                  If ec.end_result() Then
                                      Return goto_end()
                                  Else
                                      shutdown(client)
                                      Return False
                                  End If
                              End Function)
    End Function

    <Extension()> Public Function answer(ByVal client As TcpClient,
                                         ByVal handle As Func(Of Byte(), pointer(Of Byte()), event_comb),
                                         Optional ByVal send_rate_sec As Int32 = _
                                                            default_value.send_rate_sec,
                                         Optional ByVal response_timeout_ms As Int64 = _
                                                            default_value.response_timeout_ms,
                                         Optional ByVal receive_rate_sec As Int32 = _
                                                            default_value.receive_rate_sec) As event_comb
        Return answer(client,
                      Function(c As TcpClient) As event_comb
                          Dim ec As event_comb = Nothing
                          Dim p As pointer(Of Byte()) = Nothing
                          Return New event_comb(Function() As Boolean
                                                    If handle Is Nothing Then
                                                        Return False
                                                    End If
                                                    p = New pointer(Of Byte())()
                                                    ec = package_receive(c, p, response_timeout_ms, receive_rate_sec)
                                                    Return waitfor(ec) AndAlso
                                                           goto_next()
                                                End Function,
                                                Function() As Boolean
                                                    If ec.end_result() Then
                                                        Dim v() As Byte = Nothing
                                                        v = (+p)
                                                        p.clear()
                                                        ec = handle(v, p)
                                                        Return waitfor(ec) AndAlso
                                                               goto_next()
                                                    Else
                                                        Return False
                                                    End If
                                                End Function,
                                                Function() As Boolean
                                                    If ec.end_result() Then
                                                        If Not (+p) Is Nothing Then
                                                            ec = package_send(c, +p, send_rate_sec)
                                                            Return waitfor(ec) AndAlso
                                                                   goto_next()
                                                        Else
                                                            Return goto_end()
                                                        End If
                                                    Else
                                                        Return False
                                                    End If
                                                End Function,
                                                Function() As Boolean
                                                    Return ec.end_result() AndAlso
                                                           goto_end()
                                                End Function)
                      End Function)
    End Function

    'single answer
    <Extension()> Public Function answer(ByVal client As TcpClient,
                                         ByVal handle As Func(Of Stream, event_comb)) As event_comb
        Return answer(client,
                      Function(c As TcpClient) As event_comb
                          Return handle(c.GetStream())
                      End Function)
    End Function

    'continually answer on TcpClient until the powerpoint has been expired, or the handle returns false
    'and will release the client back to powerpoint
    Private Sub answer(ByVal c As TcpClient,
                       ByVal p As powerpoint,
                       ByVal handle As Func(Of event_comb))
        assert(Not c Is Nothing)
        assert(Not p Is Nothing)
        assert(Not handle Is Nothing)
        assert_begin(New event_comb(Function() As Boolean
                                        Dim ec As event_comb = Nothing
                                        Return waitfor(New event_comb(
                                                            Function() As Boolean
                                                                ec = poll_read(c)
                                                                Return waitfor(ec) AndAlso
                                                                       goto_next()
                                                            End Function,
                                                            Function() As Boolean
                                                                If ec.end_result() Then
                                                                    ec = handle()
                                                                    Return waitfor(ec) AndAlso
                                                                           goto_next()
                                                                Else
                                                                    Return False
                                                                End If
                                                            End Function,
                                                            Function() As Boolean
                                                                If ec.end_result() Then
                                                                    Return goto_begin()
                                                                Else
                                                                    Return False
                                                                End If
                                                            End Function)) AndAlso
                                               goto_next()
                                    End Function,
                                    Function() As Boolean
                                        Return p.release(c) AndAlso
                                               goto_end()
                                    End Function))
    End Sub

    'continually answer the request on the connection,
    'and release the connection back to powerpoint when the handle returns false
    'public following three functions to allow connection based question - answer
    'usually for non-status mode, do not need to call the following three functions directly
    <Extension> Public Sub answer(ByVal c As TcpClient,
                                  ByVal p As powerpoint,
                                  ByVal handle As Func(Of TcpClient, event_comb))
        answer(c,
               p,
               Function() As event_comb
                   Return answer(c, handle)
               End Function)
    End Sub

    <Extension()> Public Sub answer(ByVal c As TcpClient,
                                    ByVal p As powerpoint,
                                    ByVal handle As Func(Of Byte(), pointer(Of Byte()), event_comb))
        answer(c,
               p,
               Function() As event_comb
                   Return answer(c, handle, p.send_rate_sec, p.response_timeout_ms, p.receive_rate_sec)
               End Function)
    End Sub

    <Extension()> Public Sub answer(ByVal c As TcpClient,
                                    ByVal p As powerpoint,
                                    ByVal handle As Func(Of Stream, event_comb))
        answer(c,
               p,
               Function() As event_comb
                   Return answer(c, handle)
               End Function)
    End Sub

    'answer when a new connection has been generated
    <Extension()> Public Function answer(ByVal p As powerpoint,
                                         ByVal a As Action(Of TcpClient, powerpoint)) As Boolean
        If a Is Nothing OrElse p Is Nothing Then
            Return False
        Else
            Dim h As Action(Of TcpClient) =
                Sub(c As TcpClient)
                    While p.get(c)
                        a(c, p)
                    End While
                End Sub
            AddHandler p.connection_generated, Sub(c) h(c)
            h(Nothing)
            Return True
        End If
    End Function

    <Extension()> Public Function answer(ByVal p As powerpoint,
                                         ByVal handle As Func(Of TcpClient, event_comb)) As Boolean
        If handle Is Nothing Then
            Return False
        Else
            Return answer(p, Sub(x As TcpClient, y As powerpoint)
                                 answer(x, y, handle)
                             End Sub)
        End If
    End Function

    <Extension()> Public Function answer(ByVal p As powerpoint,
                                         ByVal handle As Func(Of Byte(), pointer(Of Byte()), event_comb)) As Boolean
        If handle Is Nothing Then
            Return False
        Else
            Return answer(p, Sub(x As TcpClient, y As powerpoint)
                                 answer(x, y, handle)
                             End Sub)
        End If
    End Function

    <Extension()> Public Function answer(ByVal p As powerpoint,
                                         ByVal handle As Func(Of Stream, event_comb)) As Boolean
        If handle Is Nothing Then
            Return False
        Else
            Return answer(p, Sub(x As TcpClient, y As powerpoint)
                                 answer(x, y, handle)
                             End Sub)
        End If
    End Function

    'the answer will work on the specific named tcp connections, even the powerpoint has been changed
    Private Function answer(ByVal name As String,
                            ByVal handle As Func(Of powerpoint, Boolean),
                            ByVal stopping As _do(Of Boolean)) As Boolean
        If handle Is Nothing OrElse stopping Is Nothing Then
            Return False
        ElseIf String.IsNullOrEmpty(name) Then
            Return False
        Else
            Dim ec As event_comb = Nothing
            Dim p As powerpoint = Nothing
            begin_lifetime_event_comb(stopping,
                                      Function() As Boolean
                                          Dim t As powerpoint = Nothing
                                          If connection_manager.get(name, t) AndAlso
                                             object_compare(t, p) <> 0 Then
                                              p = t
                                              assert(handle(p))
                                              Return True
                                          Else
                                              Return waitfor(constants.interval_ms.answer_powerpoint_change)
                                          End If
                                      End Function)
            Return True
        End If
    End Function

    Public Function answer(ByVal name As String,
                           ByVal handle As Action(Of TcpClient, powerpoint),
                           ByVal stopping As _do(Of Boolean)) As Boolean
        If handle Is Nothing Then
            Return False
        Else
            Return answer(name, Function(p As powerpoint) answer(p, handle), stopping)
        End If
    End Function

    Public Function answer(ByVal name As String,
                           ByVal handle As Func(Of TcpClient, event_comb),
                           ByVal stopping As _do(Of Boolean)) As Boolean
        If handle Is Nothing Then
            Return False
        Else
            Return answer(name, Function(p As powerpoint) answer(p, handle), stopping)
        End If
    End Function

    Public Function answer(ByVal name As String,
                           ByVal handle As Func(Of Byte(), pointer(Of Byte()), event_comb),
                           ByVal stopping As _do(Of Boolean)) As Boolean
        If handle Is Nothing Then
            Return False
        Else
            Return answer(name, Function(p As powerpoint) answer(p, handle), stopping)
        End If
    End Function

    Public Function answer(ByVal name As String,
                           ByVal handle As Func(Of Stream, event_comb),
                           ByVal stopping As _do(Of Boolean)) As Boolean
        If handle Is Nothing Then
            Return False
        Else
            Return answer(name, Function(p As powerpoint) answer(p, handle), stopping)
        End If
    End Function

    Public Function answer(ByVal name As String,
                           ByVal handle As Action(Of TcpClient, powerpoint),
                           ByVal exp As wrapper(Of singleentry)) As Boolean
        If exp Is Nothing Then
            Return False
        Else
            Return answer(name, handle, AddressOf exp.in_use)
        End If
    End Function

    Public Function answer(ByVal name As String,
                           ByVal handle As Func(Of TcpClient, event_comb),
                           ByVal exp As wrapper(Of singleentry)) As Boolean
        If exp Is Nothing Then
            Return False
        Else
            Return answer(name, handle, AddressOf exp.in_use)
        End If
    End Function

    Public Function answer(ByVal name As String,
                           ByVal handle As Func(Of Byte(), pointer(Of Byte()), event_comb),
                           ByVal exp As wrapper(Of singleentry)) As Boolean
        If exp Is Nothing Then
            Return False
        Else
            Return answer(name, handle, AddressOf exp.in_use)
        End If
    End Function

    Public Function answer(ByVal name As String,
                           ByVal handle As Func(Of Stream, event_comb),
                           ByVal exp As wrapper(Of singleentry)) As Boolean
        If exp Is Nothing Then
            Return False
        Else
            Return answer(name, handle, AddressOf exp.in_use)
        End If
    End Function

    Public Function answer(ByVal name As String,
                           ByVal handle As Action(Of TcpClient, powerpoint)) As Boolean
        Return answer(name, handle, AddressOf application_lifetime.stopping)
    End Function

    Public Function answer(ByVal name As String,
                           ByVal handle As Func(Of TcpClient, event_comb)) As Boolean
        Return answer(name, handle, AddressOf application_lifetime.stopping)
    End Function

    Public Function answer(ByVal name As String,
                           ByVal handle As Func(Of Byte(), pointer(Of Byte()), event_comb)) As Boolean
        Return answer(name, handle, AddressOf application_lifetime.stopping)
    End Function

    Public Function answer(ByVal name As String,
                           ByVal handle As Func(Of Stream, event_comb)) As Boolean
        Return answer(name, handle, AddressOf application_lifetime.stopping)
    End Function
End Module
